#include "player_simulator.h"

// Constructor
PlayerSimulator::PlayerSimulator() : rng(std::random_device{}()) {
    std::srand(std::time(nullptr));
}

int PlayerSimulator::getRandomSkill(int baseScore) {
    // Generate skill with average 70, very limited high performers (less than 5%)
    std::normal_distribution<double> dist(baseScore, 12); // Reduced variance
    int skill = static_cast<int>(dist(rng));
    
    // Ensure range 0-100
    skill = std::max(0, std::min(100, skill));
    
    // Additional restriction: very few players should exceed 85
    if (skill > 85) {
        // Only 5% chance for skill > 85, otherwise clamp to 85
        std::uniform_real_distribution<double> chanceDist(0.0, 1.0);
        if (chanceDist(rng) > 0.05) {
            skill = 85;
        }
    }
    
    return skill;
}

std::string PlayerSimulator::getCountryByWeight() {
    std::vector<int> weights;
    int totalWeight = 0;
    
    for (const auto& country : COUNTRIES) {
        weights.push_back(country.populationWeight);
        totalWeight += country.populationWeight;
    }
    
    std::uniform_int_distribution<int> dist(0, totalWeight - 1);
    int randomValue = dist(rng);
    
    int cumulativeWeight = 0;
    for (size_t i = 0; i < COUNTRIES.size(); ++i) {
        cumulativeWeight += weights[i];
        if (randomValue < cumulativeWeight) {
            return COUNTRIES[i].name;
        }
    }
    
    return COUNTRIES[0].name; // Fallback
}

std::string PlayerSimulator::generateNameByCountry(const std::string& countryCode) {
    std::string firstName, lastName, fullName;
    
    if (countryCode == "CN") {
        // Chinese names
        std::uniform_int_distribution<int> firstDist(0, CHINESE_FIRST_NAMES.size() - 1);
        std::uniform_int_distribution<int> lastDist(0, CHINESE_LAST_NAMES.size() - 1);
        
        firstName = CHINESE_FIRST_NAMES[firstDist(rng)];
        lastName = CHINESE_LAST_NAMES[lastDist(rng)];
        fullName = lastName + firstName; // Chinese name order
    } else if (countryCode == "KR") {
        // Korean names
        std::uniform_int_distribution<int> firstDist(0, KOREAN_FIRST_NAMES.size() - 1);
        std::uniform_int_distribution<int> lastDist(0, KOREAN_LAST_NAMES.size() - 1);
        
        firstName = KOREAN_FIRST_NAMES[firstDist(rng)];
        lastName = KOREAN_LAST_NAMES[lastDist(rng)];
        fullName = lastName + " " + firstName;
    } else if (countryCode == "JP") {
        // Japanese names
        std::uniform_int_distribution<int> firstDist(0, JAPANESE_FIRST_NAMES.size() - 1);
        std::uniform_int_distribution<int> lastDist(0, JAPANESE_LAST_NAMES.size() - 1);
        
        firstName = JAPANESE_FIRST_NAMES[firstDist(rng)];
        lastName = JAPANESE_LAST_NAMES[lastDist(rng)];
        fullName = lastName + " " + firstName;
    } else if (countryCode == "RU") {
        // Russian names
        std::uniform_int_distribution<int> firstDist(0, RUSSIAN_FIRST_NAMES.size() - 1);
        std::uniform_int_distribution<int> lastDist(0, RUSSIAN_LAST_NAMES.size() - 1);
        
        firstName = RUSSIAN_FIRST_NAMES[firstDist(rng)];
        lastName = RUSSIAN_LAST_NAMES[lastDist(rng)];
        fullName = firstName + " " + lastName;
    } else if (countryCode == "FR") {
        // French names
        std::uniform_int_distribution<int> firstDist(0, FRENCH_FIRST_NAMES.size() - 1);
        std::uniform_int_distribution<int> lastDist(0, FRENCH_LAST_NAMES.size() - 1);
        
        firstName = FRENCH_FIRST_NAMES[firstDist(rng)];
        lastName = FRENCH_LAST_NAMES[lastDist(rng)];
        fullName = firstName + " " + lastName;
    } else if (countryCode == "DE") {
        // German names
        std::uniform_int_distribution<int> firstDist(0, GERMAN_FIRST_NAMES.size() - 1);
        std::uniform_int_distribution<int> lastDist(0, GERMAN_LAST_NAMES.size() - 1);
        
        firstName = GERMAN_FIRST_NAMES[firstDist(rng)];
        lastName = GERMAN_LAST_NAMES[lastDist(rng)];
        fullName = firstName + " " + lastName;
    } else {
        // English names for all other countries
        std::uniform_int_distribution<int> firstDist(0, ENGLISH_FIRST_NAMES.size() - 1);
        std::uniform_int_distribution<int> lastDist(0, ENGLISH_LAST_NAMES.size() - 1);
        
        firstName = ENGLISH_FIRST_NAMES[firstDist(rng)];
        lastName = ENGLISH_LAST_NAMES[lastDist(rng)];
        fullName = firstName + " " + lastName;
    }
    
    return fullName;
}

double PlayerSimulator::calculateOverallScore(const GamingSkills& skills) {
    // Gun skills (40% total)
    double gunScore = (skills.recoilControl * 0.15 + 
                      skills.positioning * 0.10 + 
                      skills.sniping * 0.10 + 
                      skills.sprayTransfer * 0.05);
    
    // Movement skills (25% total)
    double movementScore = (skills.movementControl * 0.10 + 
                           skills.mobility * 0.08 + 
                           skills.jumpControl * 0.07);
    
    // Other skills (35% total)
    double otherScore = (skills.utilities * 0.08 + 
                        skills.leadership * 0.10 + 
                        skills.clutchAbility * 0.09 + 
                        skills.mentality * 0.08);
    
    return gunScore + movementScore + otherScore;
}

void PlayerSimulator::generateProfessionalStats(Player& player) {
    if (!player.info.isProfessional) {
        player.proStats = {0, 0, 0.0, 0, 0, 0, 0, 0, 0, 0};
        return;
    }
    
    // Generate stats based on overall score and country esports support
    double multiplier = player.overallScore / 100.0;
    int esportsSupport = 70; // Default
    
    // Find country esports support
    for (const auto& country : COUNTRIES) {
        if (country.name == player.info.nationality) {
            esportsSupport = country.esportsSupport;
            break;
        }
    }
    
    player.proStats.kills = static_cast<int>(multiplier * 2000 + std::rand() % 1000);
    player.proStats.deaths = static_cast<int>(multiplier * 1500 + std::rand() % 800);
    player.proStats.kdRatio = static_cast<double>(player.proStats.kills) / std::max(1, player.proStats.deaths);
    player.proStats.matchRecord = static_cast<int>(multiplier * 500 + std::rand() % 200);
    player.proStats.mvpCount = static_cast<int>(multiplier * 50 + std::rand() % 30);
    
    // Historical rankings based on performance
    // Historical rankings - all set to 0 for initial player generation
    player.proStats.globalTop100Count = 0;
    player.proStats.globalTop50Count = 0;
    player.proStats.globalTop10Count = 0;
    player.proStats.globalTop3Count = 0;
    player.proStats.globalTop1Count = 0;
}

void PlayerSimulator::calculateRankings() {
    // Sort players by overall score
    std::vector<Player> sortedPlayers = players;
    std::sort(sortedPlayers.begin(), sortedPlayers.end(), 
              [](const Player& a, const Player& b) {
                  return a.overallScore > b.overallScore;
              });
    
    // Assign global rankings
    for (size_t i = 0; i < sortedPlayers.size(); ++i) {
        sortedPlayers[i].globalRanking = i + 1;
    }
    
    // Calculate domestic rankings
    std::map<std::string, std::vector<Player*>> countryPlayers;
    for (auto& player : sortedPlayers) {
        countryPlayers[player.info.nationality].push_back(&player);
    }
    
    for (auto& countryPair : countryPlayers) {
        std::sort(countryPair.second.begin(), countryPair.second.end(),
                  [](const Player* a, const Player* b) {
                      return a->overallScore > b->overallScore;
                  });
        
        for (size_t i = 0; i < countryPair.second.size(); ++i) {
            countryPair.second[i]->domesticRanking = i + 1;
        }
    }
    
    // Update players vector
    players = sortedPlayers;
}

void PlayerSimulator::generatePlayers(int count) {
    players.clear();
    
    for (int i = 0; i < count; ++i) {
        Player player;
        player.id = i + 1;
        
        // Generate country first
        std::string countryName = getCountryByWeight();
        player.info.nationality = countryName;
        
        // Find country code for name generation
        std::string countryCode = "US"; // Default
        for (const auto& country : COUNTRIES) {
            if (country.name == countryName) {
                countryCode = country.code;
                break;
            }
        }
        
        // Generate name
        std::string fullName = generateNameByCountry(countryCode);
        
        // Parse name (simple split by space, if no space, assume all first name)
        size_t spacePos = fullName.find(' ');
        if (spacePos != std::string::npos) {
            player.info.firstName = fullName.substr(0, spacePos);
            player.info.lastName = fullName.substr(spacePos + 1);
        } else {
            player.info.firstName = fullName;
            player.info.lastName = "";
        }
        player.info.fullName = fullName;
        
        // Generate basic info
        std::uniform_int_distribution<int> ageDist(16, 35);
        std::uniform_int_distribution<int> agreeablenessDist(30, 100);
        std::uniform_int_distribution<int> passionDist(40, 100);
        
        player.info.age = ageDist(rng);
        player.info.agreeableness = agreeablenessDist(rng);
        player.info.passion = passionDist(rng);
        
        // Economic capacity based on country
        double economicFactor = 1.0;
        for (const auto& country : COUNTRIES) {
            if (country.name == countryName) {
                economicFactor = country.economicLevel;
                break;
            }
        }
        player.info.economicCapacity = economicFactor * (50 + std::rand() % 51);
        
        // Professional status (default: false - all players start as amateur)
        player.info.isProfessional = false;
        player.info.externalFactor = 0.0; // Initialize external factor to default value
        
        // Friends system initialization
        player.info.friends.clear();     // Initialize empty friends set
        
        if (player.info.isProfessional) {
            player.info.region = "Professional";
            player.info.teamId = 1000 + (std::rand() % 500);
            player.info.teamName = "Team " + std::to_string(player.info.teamId);
            player.info.salary = economicFactor * (50000 + std::rand() % 200000);
        } else {
            player.info.region = "Amateur";
            player.info.teamId = -1;
            player.info.teamName = "";
            player.info.salary = 0;
        }
        
        // Generate correlated skills
        int baseSkill = getRandomSkill();
        
        player.skills.recoilControl = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.positioning = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.sniping = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.sprayTransfer = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.movementControl = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.mobility = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.jumpControl = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.utilities = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.leadership = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.clutchAbility = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        player.skills.mentality = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
        
        // Calculate overall score
        player.overallScore = calculateOverallScore(player.skills);
        
        // Set friends limit based on overall score
        // Base limit is 10, increases to 15 if score > 70, to 25 if score > 80, and to 40 if score > 90
        if (player.overallScore > 90) {
            player.info.maxFriends = 40;
            player.info.baseMaxFriends = 40;
        } else if (player.overallScore > 80) {
            player.info.maxFriends = 25;
            player.info.baseMaxFriends = 25;
        } else if (player.overallScore > 70) {
            player.info.maxFriends = 15;
            player.info.baseMaxFriends = 15;
        } else {
            player.info.maxFriends = 10;
            player.info.baseMaxFriends = 10;
        }
        
        // Generate professional stats
        generateProfessionalStats(player);
        
        players.push_back(player);
    }
    
    // Calculate rankings
    calculateRankings();
}

const Player& PlayerSimulator::getPlayer(int id) const {
    static Player emptyPlayer; // Fallback
    for (const auto& player : players) {
        if (player.id == id) {
            return player;
        }
    }
    return emptyPlayer;
}

void PlayerSimulator::displayPlayer(int playerId) {
    const Player& player = getPlayer(playerId);
    
    if (player.id == 0) {
        std::cout << "Player not found!" << std::endl;
        return;
    }
    
    std::cout << "\n=== Player Information ===" << std::endl;
    std::cout << "ID: " << player.id << std::endl;
    std::cout << "Name: " << player.info.fullName << std::endl;
    std::cout << "Nationality: " << player.info.nationality << std::endl;
    std::cout << "Age: " << player.info.age << std::endl;
    std::cout << "Overall Rating: " << std::fixed << std::setprecision(2) << player.overallScore << std::endl;
    // Calculate ranking percentages
    double globalPercentile = 100.0 * (players.size() - player.globalRanking + 1) / players.size();
    
    // Count domestic players
    int domesticCount = 0;
    for (const auto& p : players) {
        if (p.info.nationality == player.info.nationality) {
            domesticCount++;
        }
    }
    double domesticPercentile = 100.0 * (domesticCount - player.domesticRanking + 1) / domesticCount;
    
    std::cout << "Global Ranking: #" << player.globalRanking << " (" << std::fixed << std::setprecision(1) << globalPercentile << "%)" << std::endl;
    std::cout << "Domestic Ranking: #" << player.domesticRanking << " (" << domesticPercentile << "%) in " << player.info.nationality << std::endl;
    std::cout << "\n--- Personality Traits ---" << std::endl;
    std::cout << "Agreeableness: " << player.info.agreeableness << std::endl;
    std::cout << "Passion: " << player.info.passion << std::endl;
    std::cout << "Economic Capacity: " << player.info.economicCapacity << std::endl;
    
    std::cout << "\n--- Gaming Skills ---" << std::endl;
    std::cout << "Gun Skills (40% weight):" << std::endl;
    std::cout << "  Recoil Control: " << player.skills.recoilControl << std::endl;
    std::cout << "  Positioning: " << player.skills.positioning << std::endl;
    std::cout << "  Sniping: " << player.skills.sniping << std::endl;
    std::cout << "  Spray Transfer: " << player.skills.sprayTransfer << std::endl;
    
    std::cout << "\nMovement Skills (25% weight):" << std::endl;
    std::cout << "  Movement Control: " << player.skills.movementControl << std::endl;
    std::cout << "  Mobility: " << player.skills.mobility << std::endl;
    std::cout << "  Jump Control: " << player.skills.jumpControl << std::endl;
    
    std::cout << "\nOther Skills (35% weight):" << std::endl;
    std::cout << "  Utilities Usage: " << player.skills.utilities << std::endl;
    std::cout << "  Leadership Ability: " << player.skills.leadership << std::endl;
    std::cout << "  Clutch Ability: " << player.skills.clutchAbility << std::endl;
    std::cout << "  Mentality: " << player.skills.mentality << std::endl;
    
    if (player.info.isProfessional) {
        std::cout << "\n--- Professional Career ---" << std::endl;
        std::cout << "Region: " << player.info.region << std::endl;
        std::cout << "Team: " << player.info.teamName << " (ID: " << player.info.teamId << ")" << std::endl;
        std::cout << "Salary: $" << std::fixed << std::setprecision(0) << player.info.salary << std::endl;
        std::cout << "K/D Ratio: " << std::fixed << std::setprecision(2) << player.proStats.kdRatio << std::endl;
        std::cout << "Total Kills: " << player.proStats.kills << std::endl;
        std::cout << "Total Deaths: " << player.proStats.deaths << std::endl;
        std::cout << "Match Record: " << player.proStats.matchRecord << std::endl;
        std::cout << "MVP Count: " << player.proStats.mvpCount << std::endl;
        
        std::cout << "\nHistorical Achievements:" << std::endl;
        if (player.proStats.globalTop100Count > 0)
            std::cout << "  Global Top 100: " << player.proStats.globalTop100Count << " times" << std::endl;
        if (player.proStats.globalTop50Count > 0)
            std::cout << "  Global Top 50: " << player.proStats.globalTop50Count << " times" << std::endl;
        if (player.proStats.globalTop10Count > 0)
            std::cout << "  Global Top 10: " << player.proStats.globalTop10Count << " times" << std::endl;
        if (player.proStats.globalTop3Count > 0)
            std::cout << "  Global Top 3: " << player.proStats.globalTop3Count << " times" << std::endl;
        if (player.proStats.globalTop1Count > 0)
            std::cout << "  Champion: " << player.proStats.globalTop1Count << " times" << std::endl;
    } else {
        std::cout << "\n--- Status ---" << std::endl;
        std::cout << "Amateur Player" << std::endl;
    }
    std::cout << "============================\n" << std::endl;
}

void PlayerSimulator::findPlayersByScoreRange(double minScore, double maxScore) {
    int count = 0;
    for (const auto& player : players) {
        if (player.overallScore >= minScore && player.overallScore <= maxScore) {
            count++;
        }
    }
    std::cout << "Players with rating between " << minScore << " and " << maxScore << ": " << count << std::endl;
}

void PlayerSimulator::findPlayersByRankingRange(int minRank, int maxRank) {
    std::cout << "Players with ranking between " << minRank << " and " << maxRank << ":" << std::endl;
    for (const auto& player : players) {
        if (player.globalRanking >= minRank && player.globalRanking <= maxRank) {
            std::cout << "#" << player.globalRanking << " (ID:" << player.id << ") - " << player.info.fullName 
                     << " (" << player.info.nationality << ") - Rating: " 
                     << std::fixed << std::setprecision(2) << player.overallScore << std::endl;
        }
    }
}

void PlayerSimulator::comparePlayers(int playerId1, int playerId2) {
    const Player& player1 = getPlayer(playerId1);
    const Player& player2 = getPlayer(playerId2);
    
    if (player1.id == 0 || player2.id == 0) {
        std::cout << "One or both players not found!" << std::endl;
        return;
    }
    
    std::cout << "\n=== Player Comparison ===" << std::endl;
    std::cout << player1.info.fullName << " vs " << player2.info.fullName << std::endl;
    std::cout << "Overall Rating: " << player1.overallScore << " vs " << player2.overallScore << std::endl;
    std::cout << "Global Ranking: #" << player1.globalRanking << " vs #" << player2.globalRanking << std::endl;
    
    std::cout << "\nSkill Comparison:" << std::endl;
    std::cout << std::setw(25) << std::left << "Skill" << std::setw(10) << player1.info.fullName.substr(0, 10) 
             << std::setw(10) << player2.info.fullName.substr(0, 10) << std::endl;
    std::cout << std::string(45, '-') << std::endl;
    
    std::cout << std::setw(25) << "Overall Rating" << std::setw(10) << player1.overallScore 
             << std::setw(10) << player2.overallScore << std::endl;
    std::cout << std::setw(25) << "Recoil Control" << std::setw(10) << player1.skills.recoilControl 
             << std::setw(10) << player2.skills.recoilControl << std::endl;
    std::cout << std::setw(25) << "Positioning" << std::setw(10) << player1.skills.positioning 
             << std::setw(10) << player2.skills.positioning << std::endl;
    std::cout << std::setw(25) << "Sniping" << std::setw(10) << player1.skills.sniping 
             << std::setw(10) << player2.skills.sniping << std::endl;
    std::cout << std::setw(25) << "Movement Control" << std::setw(10) << player1.skills.movementControl 
             << std::setw(10) << player2.skills.movementControl << std::endl;
    std::cout << std::setw(25) << "Mentality" << std::setw(10) << player1.skills.mentality 
             << std::setw(10) << player2.skills.mentality << std::endl;
    
    if (player1.info.isProfessional && player2.info.isProfessional) {
        std::cout << "\nProfessional Data:" << std::endl;
        std::cout << std::setw(25) << "K/D Ratio" << std::setw(10) << player1.proStats.kdRatio 
                 << std::setw(10) << player2.proStats.kdRatio << std::endl;
        std::cout << std::setw(25) << "MVP Count" << std::setw(10) << player1.proStats.mvpCount 
                 << std::setw(10) << player2.proStats.mvpCount << std::endl;
    }
    std::cout << "============================\n" << std::endl;
}

void PlayerSimulator::resetAndGenerate(int playerCount) {
    std::cout << "Generating " << playerCount << " players..." << std::endl;
    generatePlayers(playerCount);
    std::cout << "Generation complete!" << std::endl;
    std::cout << "Total players: " << players.size() << std::endl;
    
    // Show some statistics
    int professionalCount = 0;
    double avgScore = 0;
    for (const auto& player : players) {
        if (player.info.isProfessional) professionalCount++;
        avgScore += player.overallScore;
    }
    avgScore /= players.size();
    
    std::cout << "Professional players: " << professionalCount << std::endl;
    std::cout << "Average overall rating: " << std::fixed << std::setprecision(2) << avgScore << std::endl;
}

void PlayerSimulator::showMainMenu() {
    std::cout << "\n========== Esports Player Simulator ==========" << std::endl;
    std::cout << "1. Generate players" << std::endl;
    std::cout << "2. Find player (ID)" << std::endl;
    std::cout << "3. Find players by rating range" << std::endl;
    std::cout << "4. Find players by ranking range" << std::endl;
    std::cout << "5. Compare two players" << std::endl;
    std::cout << "6. Show country rankings" << std::endl;
    std::cout << "7. List available countries" << std::endl;
    std::cout << "8. Set player external factor" << std::endl;
    std::cout << "9. Show professional data" << std::endl;
    std::cout << "10. Update player abilities based on age" << std::endl;
    std::cout << "11. Regenerate players" << std::endl;
    std::cout << "12. Add friend" << std::endl;
    std::cout << "13. Remove friend" << std::endl;
    std::cout << "14. Display player's friends" << std::endl;
    std::cout << "0. Exit" << std::endl;
    std::cout << "=============================================" << std::endl;
    std::cout << "Please select an operation: ";
}

bool PlayerSimulator::handleMenuChoice(int choice) {
    int id, count, minVal, maxVal;
    switch (choice) {
        case 1:
            std::cout << "Please enter the number of players to generate: ";
            std::cin >> count;
            resetAndGenerate(count);
            break;
            
        case 2:
            std::cout << "Please enter player ID: ";
            std::cin >> id;
            displayPlayer(id);
            break;
            
        case 3:
            std::cout << "Please enter minimum rating: ";
            std::cin >> minVal;
            std::cout << "Please enter maximum rating: ";
            std::cin >> maxVal;
            findPlayersByScoreRange(minVal, maxVal);
            break;
            
        case 4:
            std::cout << "Please enter minimum ranking: ";
            std::cin >> minVal;
            std::cout << "Please enter maximum ranking: ";
            std::cin >> maxVal;
            findPlayersByRankingRange(minVal, maxVal);
            break;
            
        case 5:
            std::cout << "Please enter first player ID: ";
            std::cin >> id;
            int id2;
            std::cout << "Please enter second player ID: ";
            std::cin >> id2;
            comparePlayers(id, id2);
            break;
            
        case 6:
            {
                std::string country;
                std::cout << "Please enter country name: ";
                std::cin >> country;
                showCountryRankings(country);
            }
            break;
            
        case 7:
            listAvailableCountries();
            break;
            
        case 8: {
            std::cout << "Please enter player ID: ";
            std::cin >> id;
            double factor;
            std::cout << "Please enter external factor value: ";
            std::cin >> factor;
            setPlayerExternalFactor(id, factor);
            break;
        }
            
        case 9:
            std::cout << "\n=== Professional Data ===" << std::endl;
            for (const auto& player : players) {
                if (player.info.isProfessional) {
                    std::cout << "Name: " << player.info.fullName << std::endl;
                    std::cout << "Region: " << player.info.region << std::endl;
                    std::cout << "Team: " << player.info.teamName << std::endl;
                    std::cout << "Salary: $" << player.info.salary << " USD" << std::endl;
                    std::cout << "-----------" << std::endl;
                }
            }
            break;
            
        case 10:
            updatePlayerAbilities();
            break;
            
        case 11:
            displayCountryRankings();
            break;
            
        case 12: {
            int playerId, friendId;
            std::cout << "Please enter player ID: ";
            std::cin >> playerId;
            std::cout << "Please enter friend ID: ";
            std::cin >> friendId;
            addFriend(playerId, friendId);
            break;
        }
            
        case 13: {
            int playerId, friendId;
            std::cout << "Please enter player ID: ";
            std::cin >> playerId;
            std::cout << "Please enter friend ID: ";
            std::cin >> friendId;
            removeFriend(playerId, friendId);
            break;
        }
            
        case 14: {
            int playerId;
            std::cout << "Please enter player ID: ";
            std::cin >> playerId;
            displayFriends(playerId);
            break;
        }
            
        case 0:
            std::cout << "Thank you for using the Esports Player Simulator!" << std::endl;
            return false;
            
        default:
            std::cout << "Invalid choice, please try again." << std::endl;
    }
    return true;
}

// Display national leaderboard
void PlayerSimulator::showCountryRankings(const std::string& country) {
    std::cout << "\n=== " << country << " Leaderboard ===" << std::endl;

    // Collect all players from this country
    std::vector<Player*> countryPlayers;
    for (auto& player : players) {
        if (player.info.nationality == country) {
            countryPlayers.push_back(&player);
        }
    }

    if (countryPlayers.empty()) {
        std::cout << "No players found for this country." << std::endl;
        return;
    }

    // Prompt for rank range
    int startRank, endRank;
    std::cout << "Total players from " << country << ": " << countryPlayers.size() << std::endl;
    std::cout << "Enter rank range to display (start end): ";
    std::cin >> startRank >> endRank;

    // Validate range
    if (startRank < 1) startRank = 1;
    if (endRank > static_cast<int>(countryPlayers.size())) endRank = countryPlayers.size();
    if (startRank > endRank) {
        std::cout << "Invalid rank range!" << std::endl;
        return;
    }

    // Sort by overall rating (descending)
    std::sort(countryPlayers.begin(), countryPlayers.end(),
        [](const Player* a, const Player* b) {
            return a->overallScore > b->overallScore;
        });

    // Display leaderboard (with global percentile context)
    for (int i = startRank - 1; i < endRank && i < static_cast<int>(countryPlayers.size()); ++i) {
        Player* player = countryPlayers[i];
        // Calculate global percentile based on global ranking
        double globalPercentile = 100.0 * (players.size() - player->globalRanking + 1) / players.size();

        std::cout << "#" << (i + 1) << " (ID:" << player->id << ") - "
            << player->info.fullName
            << " | Rating: " << std::fixed << std::setprecision(2) << player->overallScore
            << " | Global Percentile: " << std::setprecision(3) << globalPercentile << "%"
            << " | Age: " << player->info.age << std::endl;
    }

    std::cout << "Total players from " << country << ": " << countryPlayers.size() << std::endl;
    std::cout << "============================\n" << std::endl;
}

void PlayerSimulator::listAvailableCountries() {
    std::set<std::string> countries;
    for (const auto& player : players) {
        countries.insert(player.info.nationality);
    }

    std::cout << "\n=== Available Countries ===" << std::endl;
    int count = 0;
    for (const auto& country : countries) {
        std::cout << country << " ";
        count++;
        if (count % 5 == 0) {
            std::cout << std::endl;
        }
    }
    if (count % 5 != 0) {
        std::cout << std::endl;
    }
    std::cout << "Total: " << countries.size() << " countries" << std::endl;
    std::cout << "============================\n" << std::endl;
}

void PlayerSimulator::displayCountryRankings() {
    std::map<std::string, std::vector<Player*>> countryPlayers;
    
    // Group by country
    for (auto& player : players) {
        countryPlayers[player.info.nationality].push_back(&player);
    }
    
    // Calculate average score and player count for each country
    struct CountryStats {
        std::string name;
        int playerCount;
        double avgScore;
        Player* topPlayer;
    };
    
    std::vector<CountryStats> countryStats;
    
    for (auto& countryPair : countryPlayers) {
        CountryStats stats;
        stats.name = countryPair.first;
        stats.playerCount = countryPair.second.size();
        
        double totalScore = 0;
        Player* topPlayer = nullptr;
        double topScore = -1;
        
        for (Player* player : countryPair.second) {
            totalScore += player->overallScore;
            if (player->overallScore > topScore) {
                topScore = player->overallScore;
                topPlayer = player;
            }
        }
        
        stats.avgScore = totalScore / countryPair.second.size();
        stats.topPlayer = topPlayer;
        countryStats.push_back(stats);
    }
    
    // Sort by average score
    std::sort(countryStats.begin(), countryStats.end(),
              [](const CountryStats& a, const CountryStats& b) {
                  return a.avgScore > b.avgScore;
              });
    
    std::cout << "\n=== National Leaderboard Overview ===" << std::endl;
    std::cout << std::setw(20) << std::left << "Country"
        << std::setw(8) << "Players"
        << std::setw(12) << "Avg Rating"
        << std::setw(15) << "Top Player"
        << std::setw(10) << "Top Score" << std::endl;
    
    for (const auto& stats : countryStats) {
        std::cout << std::setw(20) << std::left << stats.name
                 << std::setw(8) << stats.playerCount
                 << std::setw(12) << std::fixed << std::setprecision(2) << stats.avgScore
                 << std::setw(15) << stats.topPlayer->info.fullName.substr(0, 14)
                 << std::setw(10) << std::fixed << std::setprecision(2) << stats.topPlayer->overallScore << std::endl;
    }
    
    std::cout << "============================\n" << std::endl;
}

void PlayerSimulator::updatePlayerAbilities() {
    std::cout << "\n=== Updating Player Abilities Based on Age ===" << std::endl;
    
    // Create a uniform distribution for random adjustments (-3 to 3)
    std::uniform_int_distribution<int> adjustmentDist(-3, 3);
    std::uniform_int_distribution<int> newAgeDist(18, 25); // For generating new players aged 18-25
    
    int updatedPlayers = 0;
    int replacedPlayers = 0;
    
    // First, update all players' ages and abilities
    for (auto& player : players) {
        // Increment player's age
        player.info.age++;
        
        // Check if player has reached retirement age (40)
        if (player.info.age >= 40) {
            // Clean up friend relationships before retiring
            // Remove this player from all friends' friend lists
            for (int friendId : player.info.friends) {
                for (auto& friendPlayer : players) {
                    if (friendPlayer.id == friendId) {
                        friendPlayer.info.friends.erase(player.id);
                        break;
                    }
                }
            }
            // Clear this player's friend list
            player.info.friends.clear();
            
            // Generate a new player to replace the retired one
            // Keep the same ID but update all other attributes
            int oldId = player.id;
            
            // Generate country first
            std::string countryName = getCountryByWeight();
            player.info.nationality = countryName;
            
            // Find country code for name generation
            std::string countryCode = "US"; // Default
            for (const auto& country : COUNTRIES) {
                if (country.name == countryName) {
                    countryCode = country.code;
                    break;
                }
            }
            
            // Generate name
            std::string fullName = generateNameByCountry(countryCode);
            
            // Parse name (simple split by space, if no space, assume all first name)
            size_t spacePos = fullName.find(' ');
            if (spacePos != std::string::npos) {
                player.info.firstName = fullName.substr(0, spacePos);
                player.info.lastName = fullName.substr(spacePos + 1);
            } else {
                player.info.firstName = fullName;
                player.info.lastName = "";
            }
            player.info.fullName = fullName;
            
            // Set new age (18-25)
            player.info.age = newAgeDist(rng);
            
            // Reset other personal attributes
            std::uniform_int_distribution<int> agreeablenessDist(30, 100);
            std::uniform_int_distribution<int> passionDist(40, 100);
            
            player.info.agreeableness = agreeablenessDist(rng);
            player.info.passion = passionDist(rng);
            
            // Economic capacity based on country
            double economicFactor = 1.0;
            for (const auto& country : COUNTRIES) {
                if (country.name == countryName) {
                    economicFactor = country.economicLevel;
                    break;
                }
            }
            player.info.economicCapacity = economicFactor * (50 + std::rand() % 51);
            
            // Reset professional status
            player.info.isProfessional = false;
            player.info.region = "Amateur";
            player.info.teamId = -1;
            player.info.teamName = "";
            player.info.salary = 0;
            player.info.externalFactor = 0.0; // Initialize external factor to default value
            
            // Generate new skills
            int baseSkill = getRandomSkill();
            
            player.skills.recoilControl = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.positioning = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.sniping = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.sprayTransfer = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.movementControl = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.mobility = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.jumpControl = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.utilities = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.leadership = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.clutchAbility = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            player.skills.mentality = std::max(30, std::min(100, baseSkill + std::rand() % 40 - 20));
            
            // Calculate overall score
            player.overallScore = calculateOverallScore(player.skills);
            
            // Generate professional stats
            generateProfessionalStats(player);
            
            // Reset rankings
            player.globalRanking = 0;
            player.domesticRanking = 0;
            
            // Friends system initialization for new player
            player.info.friends.clear();     // Initialize empty friends set
            
            // Set friends limit based on overall score
            if (player.overallScore > 90) {
                player.info.maxFriends = 40;
                player.info.baseMaxFriends = 40;
            } else if (player.overallScore > 80) {
                player.info.maxFriends = 25;
                player.info.baseMaxFriends = 25;
            } else if (player.overallScore > 70) {
                player.info.maxFriends = 15;
                player.info.baseMaxFriends = 15;
            } else {
                player.info.maxFriends = 10;
                player.info.baseMaxFriends = 10;
            }
            
            replacedPlayers++;
            continue; // Skip to next player as this one has been replaced
        }
        
        // Get player's age
        int age = player.info.age;
        
        // Define expected changes based on age groups
        // We'll adjust each skill based on age-related expectations
        // Young players (16-20): Slight improvement
        // Prime players (21-27): Minimal changes
        // Veteran players (28-35): Slight decline in physical skills, minimal gain in experience
        
        // Calculate age factor for each skill category (reduced impact)
        double gunSkillFactor = 0.0;      // Recoil control, positioning, sniping, spray transfer
        double movementFactor = 0.0;      // Movement control, mobility, jump control
        double mentalFactor = 0.0;        // Utilities, leadership, clutch ability, mentality
        
        if (age <= 20) {
            // Young players improve slightly
            gunSkillFactor = 0.1;
            movementFactor = 0.15;
            mentalFactor = 0.05;
        } else if (age <= 27) {
            // Prime years, minimal changes
            gunSkillFactor = 0.05;
            movementFactor = 0.02;
            mentalFactor = 0.08;
        } else {
            // Veterans may see slight physical decline but minimal gain in experience
            gunSkillFactor = -0.05;
            movementFactor = -0.1;
            mentalFactor = 0.1;
        }
        
        // Apply changes to gun skills (ensure changes are within -3 to 3)
        player.skills.recoilControl = std::max(0, std::min(100, player.skills.recoilControl + 
            std::max(-3, std::min(3, static_cast<int>(gunSkillFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        player.skills.positioning = std::max(0, std::min(100, player.skills.positioning + 
            std::max(-3, std::min(3, static_cast<int>(gunSkillFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        player.skills.sniping = std::max(0, std::min(100, player.skills.sniping + 
            std::max(-3, std::min(3, static_cast<int>(gunSkillFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        player.skills.sprayTransfer = std::max(0, std::min(100, player.skills.sprayTransfer + 
            std::max(-3, std::min(3, static_cast<int>(gunSkillFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        
        // Apply changes to movement skills (ensure changes are within -3 to 3)
        player.skills.movementControl = std::max(0, std::min(100, player.skills.movementControl + 
            std::max(-3, std::min(3, static_cast<int>(movementFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        player.skills.mobility = std::max(0, std::min(100, player.skills.mobility + 
            std::max(-3, std::min(3, static_cast<int>(movementFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        player.skills.jumpControl = std::max(0, std::min(100, player.skills.jumpControl + 
            std::max(-3, std::min(3, static_cast<int>(movementFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        
        // Apply changes to mental skills (ensure changes are within -3 to 3)
        player.skills.utilities = std::max(0, std::min(100, player.skills.utilities + 
            std::max(-3, std::min(3, static_cast<int>(mentalFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        player.skills.leadership = std::max(0, std::min(100, player.skills.leadership + 
            std::max(-3, std::min(3, static_cast<int>(mentalFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        player.skills.clutchAbility = std::max(0, std::min(100, player.skills.clutchAbility + 
            std::max(-3, std::min(3, static_cast<int>(mentalFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        player.skills.mentality = std::max(0, std::min(100, player.skills.mentality + 
            std::max(-3, std::min(3, static_cast<int>(mentalFactor * 10 + adjustmentDist(rng) + player.info.externalFactor)))));
        
        // Recalculate overall score after adjustments
        player.overallScore = calculateOverallScore(player.skills);
        
        // Update friends limit based on overall score
        // Base limit is 15 (70+ score gives 15), increases to 25 if score > 80, and to 40 if score > 90
        // Limit only increases, never decreases
        if (player.overallScore > 90 && player.info.maxFriends < 40) {
            player.info.maxFriends = 40;
        } else if (player.overallScore > 80 && player.info.maxFriends < 25) {
            player.info.maxFriends = 25;
        } else if (player.overallScore > 70 && player.info.maxFriends < 15) {
            player.info.maxFriends = 15;
        }
        
        updatedPlayers++;
    }
    
    // Recalculate rankings after updating abilities
    calculateRankings();
    
    std::cout << "Updated abilities for " << updatedPlayers << " players based on their age." << std::endl;
    if (replacedPlayers > 0) {
        std::cout << "Replaced " << replacedPlayers << " retired players (age 40+) with new players aged 18-25." << std::endl;
    }
    std::cout << "Each attribute was adjusted within +/- 3 points with age having minimal influence on the mean." << std::endl;
    std::cout << "External factors have also been applied to all attributes." << std::endl;
    std::cout << "Global and domestic rankings have been recalculated." << std::endl;
    std::cout << "============================\n" << std::endl;
}

void PlayerSimulator::setPlayerExternalFactor(int playerId, double factor) {
    for (auto& player : players) {
        if (player.id == playerId) {
            player.info.externalFactor = factor;
            std::cout << "Set external factor for player " << playerId << " to " << factor << std::endl;
            return;
        }
    }
    std::cout << "Player with ID " << playerId << " not found." << std::endl;
}

bool PlayerSimulator::addFriend(int playerId, int friendId) {
    // Check if player and friend are the same
    if (playerId == friendId) {
        std::cout << "A player cannot be friends with themselves." << std::endl;
        return false;
    }
    
    // Find both players
    Player* player = nullptr;
    Player* friendPlayer = nullptr;
    
    for (auto& p : players) {
        if (p.id == playerId) {
            player = &p;
        } else if (p.id == friendId) {
            friendPlayer = &p;
        }
    }
    
    // Check if both players exist
    if (!player) {
        std::cout << "Player with ID " << playerId << " not found." << std::endl;
        return false;
    }
    
    if (!friendPlayer) {
        std::cout << "Player with ID " << friendId << " not found." << std::endl;
        return false;
    }
    
    // Check if already friends
    if (player->info.friends.find(friendId) != player->info.friends.end()) {
        std::cout << "Player " << playerId << " is already friends with player " << friendId << "." << std::endl;
        return false;
    }
    
    // Check if player has reached maximum friends limit
    if (player->info.friends.size() >= player->info.maxFriends) {
        std::cout << "Player " << playerId << " has reached the maximum number of friends (" << player->info.maxFriends << ")." << std::endl;
        return false;
    }
    
    // Check if friend has reached maximum friends limit
    if (friendPlayer->info.friends.size() >= friendPlayer->info.maxFriends) {
        std::cout << "Player " << friendId << " has reached the maximum number of friends (" << friendPlayer->info.maxFriends << ")." << std::endl;
        return false;
    }
    
    // Add friend relationship (bidirectional)
    player->info.friends.insert(friendId);
    friendPlayer->info.friends.insert(playerId);
    
    std::cout << "Player " << playerId << " is now friends with player " << friendId << "." << std::endl;
    return true;
}

bool PlayerSimulator::removeFriend(int playerId, int friendId) {
    // Find both players
    Player* player = nullptr;
    Player* friendPlayer = nullptr;
    
    for (auto& p : players) {
        if (p.id == playerId) {
            player = &p;
        } else if (p.id == friendId) {
            friendPlayer = &p;
        }
    }
    
    // Check if both players exist
    if (!player) {
        std::cout << "Player with ID " << playerId << " not found." << std::endl;
        return false;
    }
    
    if (!friendPlayer) {
        std::cout << "Player with ID " << friendId << " not found." << std::endl;
        return false;
    }
    
    // Check if they are actually friends
    if (player->info.friends.find(friendId) == player->info.friends.end()) {
        std::cout << "Player " << playerId << " is not friends with player " << friendId << "." << std::endl;
        return false;
    }
    
    // Remove friend relationship (bidirectional)
    player->info.friends.erase(friendId);
    friendPlayer->info.friends.erase(playerId);
    
    std::cout << "Player " << playerId << " is no longer friends with player " << friendId << "." << std::endl;
    return true;
}

void PlayerSimulator::displayFriends(int playerId) {
    // Find the player
    const Player* player = nullptr;
    
    for (const auto& p : players) {
        if (p.id == playerId) {
            player = &p;
            break;
        }
    }
    
    // Check if player exists
    if (!player) {
        std::cout << "Player with ID " << playerId << " not found." << std::endl;
        return;
    }
    
    // Display friends
    std::cout << "Player " << playerId << " (" << player->info.firstName << " " << player->info.lastName << ") has " 
              << player->info.friends.size() << " friends (max: " << player->info.maxFriends << "):" << std::endl;
    
    if (player->info.friends.empty()) {
        std::cout << "No friends." << std::endl;
        return;
    }
    
    for (int friendId : player->info.friends) {
        // Find friend's name
        for (const auto& p : players) {
            if (p.id == friendId) {
                std::cout << "  - " << friendId << ": " << p.info.firstName << " " << p.info.lastName << std::endl;
                break;
            }
        }
    }
}